<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			
			//对象的解构与数组有一个重要的不同。数组
			//的元素是按次序排列的，变量的取值由它的位置决定；
			//而对象的属性没有次序，变量必须与属性同名，才能取到正确的值。
			let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
			foo // "aaa"
			bar // "bbb"
			
			
			/*
			下面代码的第一个例子，等号左边的两个变量的次序，
			与等号右边两个同名属性的次序不一致，但是对取值
			完全没有影响。第二个例子的变量没有对应的同名属
			性，导致取不到值，最后等于undefined。
			如果解构失败，变量的值等于undefined。
			* */
			let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
			foo // "aaa"
			bar // "bbb"
			
			let { baz } = { foo: 'aaa', bar: 'bbb' };
			baz // undefined
			
			
			//对象的解构赋值，可以很方便地将现有对象的方法，赋值到某个变量。
			// 例一
			let { log, sin, cos } = Math;
			
			// 例二
			const { log } = console;
			log('hello') // hello
			
			
			
			//变量名与属性名不一致，必须写成下面这样。
			let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
			baz // "aaa"
			
			let obj = { first: 'hello', last: 'world' };
			let { first: f, last: l } = obj;
			f // 'hello'
			l // 'world'
			//也就是说，对象的解构赋值的内部机制，是先找到同名属性，
			//然后再赋给对应的变量。真正被赋值的是后者，而不是前者
			
			
			
			//注意，对象的解构赋值可以取到继承的属性。
			const obj1 = {};
			const obj2 = { foo: 'bar' };
			Object.setPrototypeOf(obj1, obj2);
			
			const { foo } = obj1;
			foo // "bar"
			
			
			
			//对象的解构也可以指定默认值。
			//默认值生效的条件是，对象的属性值严格等于undefined。
			var {x = 3} = {};
			x // 3
			
			var {x, y = 5} = {x: 1};
			x // 1
			y // 5
			
			var {x: y = 3} = {};
			y // 3
			
			var {x: y = 3} = {x: 5};
			y // 5
			
			var {x = 3} = {x: undefined};
			x // 3
			
			var {x = 3} = {x: null};
			x // null
						
			
			
			//如果要将一个已经声明的变量用于解构赋值，必须非常小心。
			// 错误的写法
			let x;
			{x} = {x: 1};
			// SyntaxError: syntax error
			
			// 正确的写法
			let x;
			({x} = {x: 1});
			
			
			
			//由于数组本质是特殊的对象，因此可以对数组进行对象属性的解构
			let arr = [1, 2, 3];
			let {0 : first, [arr.length - 1] : last} = arr;
			first // 1
			last // 3
			
			
			
			//字符串的解构赋值
			const [a, b, c, d, e] = 'hello';
			a // "h"
			b // "e"
			c // "l"
			d // "l"
			e // "o"
			//类似数组的对象都有一个length属性，因此还可以对这个属性解构赋值。
			let {length : len} = 'hello';
			len // 5
			
			
			//数值和布尔值的解构赋值 
			//解构赋值时，如果等号右边是数值和布尔值，则会先转为对象。
			//就先将其转为对象。由于undefined和null无法转为对象，
			//所以对它们进行解构赋值，都会报错。
			let {toString: s} = 123;
			s === Number.prototype.toString // true
			
			let {toString: s} = true;
			s === Boolean.prototype.toString // true
			
			let { prop: x } = undefined; // TypeError
			let { prop: y } = null; // TypeError
			
			
			
			//函数参数的解构赋值
			function add([x, y]){
			  return x + y;
			}
			
			add([1, 2]); // 3
			
			//函数参数的解构也可以使用默认值。
			function move({x = 0, y = 0} = {}) {
			  return [x, y];
			}
			
			move({x: 3, y: 8}); // [3, 8]
			move({x: 3}); // [3, 0]
			move({}); // [0, 0]
			move(); // [0, 0]
			
			function move({x, y} = { x: 0, y: 0 }) {
			  return [x, y];
			}
			move({x: 3, y: 8}); // [3, 8]
			move({x: 3}); // [3, undefined]
			move({}); // [undefined, undefined]
			move(); // [0, 0]
			
			
			
			//用途
			//输入模块的指定方法
			//加载模块时，往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰
			const { SourceMapConsumer, SourceNode } = require("source-map");
		</script>
	</body>
</html>
